﻿using JESAI.Core.Extensions.Helpers;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
namespace JESAI.Core.Util.Helpers
{
    /// <summary>
    /// 应用程序帮助类，可用来识别当前操作系统类型、程序运行持续时间
    /// </summary>
    public static class ApplicationHelper
    {
        /// <summary>
        /// 获取当前进程运行持续的时间
        /// </summary>
        public static TimeSpan GetProcessStartupDuration() =>
            DateTime.Now.Subtract(Process.GetCurrentProcess().StartTime);

        /// <summary>
        /// 判断当前操作系统是否是 <c>Windows</c>.
        /// </summary>
        public static bool IsWindows => RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

        /// <summary>
        /// 判断当前操作系统是否是<c>Linux</c>.
        /// </summary>
        public static bool IsLinux => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);

        /// <summary>
        /// 判断当前操作系统是否是<c>OSX</c>.
        /// </summary>
        public static bool IsOSX => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);

        /// <summary>
        /// 返回操作系统的类型<seealso cref="OSPlatform"/>
        /// </summary>
        public static OSPlatform OSPlatform => GetOSPlatform();

        /// <summary>
        /// 判断当前程序是否是 <c>LARGEADDRESSAWARE</c>
        /// <para>关于LARGEADDRESSAWARE,参考: <seealso href="https://helloacm.com/large-address-aware/"/></para>
        /// </summary>
        public static bool IsProcessLargeAddressAware()
        {
            using var p = Process.GetCurrentProcess();
            return IsLargeAddressAware(p.MainModule?.FileName);
        }

        /// <summary>
        /// <see href="https://helloacm.com/large-address-aware/"/>
        /// </summary>
        internal static bool IsLargeAddressAware(string file)
        {
            EnsureExceptionsHelper.NotNullOrEmptyOrWhiteSpace(file);
            var fileInfo = new FileInfo(file);
            EnsureExceptionsHelper.Exists(fileInfo);

            const int ImageFileLargeAddressAware = 0x20;

            using var stream = File.Open(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            using var reader = new BinaryReader(stream);

            //No MZ Header
            if (reader.ReadInt16() != 0x5A4D) { return false; }

            reader.BaseStream.Position = 0x3C;
            var peloc = reader.ReadInt32(); //Get the PE header location.

            reader.BaseStream.Position = peloc;

            //No PE header
            if (reader.ReadInt32() != 0x4550) { return false; }

            reader.BaseStream.Position += 0x12;
            return (reader.ReadInt16() & ImageFileLargeAddressAware) == ImageFileLargeAddressAware;
        }

        // ReSharper disable once InconsistentNaming
        private static OSPlatform GetOSPlatform()
        {
            if (IsWindows) { return OSPlatform.Windows; }
            if (IsLinux) { return OSPlatform.Linux; }
            if (IsOSX) { return OSPlatform.OSX; }
            return OSPlatform.Create("UNKNOWN");
        }

        #region 应用程序启动、退出前、退出后的事件触发机制
        private static CancellationToken _applicationStarted;
        /// <summary>
        /// Triggered when the application host has fully started.
        /// </summary>
        public static CancellationToken ApplicationStarted => _applicationStarted;

        private static CancellationToken _applicationStopped;
        /// <summary>
        /// Triggered when the application host is performing a graceful shutdown. Shutdown will block until this event completes.
        /// </summary>
        public static CancellationToken ApplicationStopped => _applicationStopped;

        private static CancellationToken _applicationStopping;
        /// <summary>
        /// Triggered when the application host is performing a graceful shutdown. Shutdown will block until this event completes.
        /// </summary>
        public static CancellationToken ApplicationStopping => _applicationStopping;

        /// <summary>
        /// 设置应用程序启动的StartedToken,如：<para></para>
        /// SetApplicationStartedToken(IHostApplicationLifetime.ApplicationStarted)
        /// </summary>
        /// <param name="cancellationToken"></param>
        public static void SetApplicationStartedToken(CancellationToken cancellationToken) => _applicationStarted = cancellationToken;

        /// <summary>
        /// 设置应用程序关闭完成后的StoppedToken,如：<para></para>
        /// SetApplicationStoppedToken(IHostApplicationLifetime.ApplicationStopped)
        /// </summary>
        /// <param name="cancellationToken"></param>
        public static void SetApplicationStoppedToken(CancellationToken cancellationToken) => _applicationStopped = cancellationToken;

        /// <summary>
        /// 设置应用程序将要关闭的的StoppingToken,如：<para></para>
        /// SetApplicationStoppingToken(IHostApplicationLifetime.ApplicationStopping)
        /// </summary>
        /// <param name="cancellationToken"></param>
        public static void SetApplicationStoppingToken(CancellationToken cancellationToken) => _applicationStopping = cancellationToken;
        #endregion
    }
}
